//
//  API.swift
//  suda
//
//  Created by youai on 2019/7/15.
//  Copyright © 2019年 youi. All rights reserved.
//

import Foundation
import CocoaLumberjack

/**
 回调返回值
 - success: 网络访问是否成功，或者返回的错误码是否为零
 - error: 网络访问失败的error对象
 - errNo: 返回错误码
 - errMsg: 返回错误信息
 - data: 返回数据
*/
struct APIResult{
    ///网络访问是否成功，或者返回的错误码是否为零
    let success : Bool
    ///网络访问失败的error对象
    let error : Error?
    ///返回错误码
    let errNo : Int?
    ///返回错误信息
    let errMsg : String?
    ///返回数据
    let data : [String:Any?]?
}

class API {
    
    static let RESULT = "result"
    static let SUCCESS = "success"
    static let MSG = "msg"
    static let MESSAGE = "message"
    static let CODE = "code"
    
    ///登录确认地址
    private static var LoginSureUrl : String = ""
    
    static func request(url:APIUrl,host:String=HOST_URL,params:[String:Any]?,useMainQueue:Bool = true,loggingLevel:DDLogLevel = .info,  callback:@escaping (APIResult)->Void){
        let queue = useMainQueue ? DispatchQueue.main : DispatchQueue.global()
        //登录API的出错日志比较特殊
        let urlString = host+url.rawValue
        func logErrorAndCallback(response:NetworkingResult<String>,errNo:Int?=nil, info:String? = nil) {
            logError("url",urlString)
            logError("params",params?.jsonString)
            if response.error != nil {
                logError("error",response.error!.localizedDescription)
            }
            logError("data",response.data)
            callback(APIResult(success: false,
                               error: response.error,
                               errNo: errNo,
                               errMsg: info ?? "数据解析失败，请稍候再试",
                               data: errNo != nil ? nil : ["data":response.data]))
            
        }

        print("URL:\(String(describing: urlString)) \n ")
        print("PostData:\n" + (anyToString(params?.jsonString) ?? ""))
        Networking.queryString(urlStr: urlString, params: params ,queue:queue) { (response) in
            if response.success && response.error == nil {
                if let result =  response.data?.trim().toJSONDictionary() {
                    print("URL:\(String(describing: urlString)) \n ")
                    print("result:\n \(String(describing: result.jsonString))" )
                    
                    if result.getString(RESULT) == "success" || result.getBool(SUCCESS) ?? false {
                        let errNo = anyToInt(result[CODE] ?? 0)
                        callback(APIResult(success: true,
                                           error: response.error,
                                           errNo: errNo,
                                           errMsg: result.getString(MSG) ?? result.getString(MESSAGE),
                                           data: result))

                    }else{
                        //获取errNo失败
//                        logErrorAndCallback(response: response, errNo: nil, info: "获取失败，请稍候再试")
                        let errNo = anyToInt(result[CODE] ?? 0)
                        if errNo == 1000013 {
                            sendTokenTomeout()
                        }
                        else if errNo == 1000016 {
                            showDefultVC()
                        }
                        else {
                            callback(APIResult(success: false,
                                               error: response.error,
                                               errNo: errNo,
                                               errMsg: result.getString(MSG) ?? result.getString(MESSAGE),
                                               data: result))
                        }
                        return
                    }
                }else{
                    //解析Json失败
                    print("URL:\(String(describing: urlString)) \n ")
                    print("result:\n \(String(describing: response.data?.trim()))" )
                    logErrorAndCallback(response: response, errNo: nil, info: "Json失败，请稍候再试")
                    return
                }
            }else{
                //网络请求失败
                print("URL:\(String(describing: urlString)) \n ")
                print("result:\n \(String(describing: response.data?.trim()))" )
                let popup = PopupBox(infoText: "请检查网络")
                popup.show(vc: UIViewController.topMostController() ?? UIViewController())
                logErrorAndCallback(response: response, errNo: nil, info: "网络访问无法完成，请稍候再试")
                return
            }
        }
    }
    
    static func formRequest(url:APIUrl,host:String=YouAi_Host,params:[String:Any]?,useMainQueue:Bool = true,loggingLevel:DDLogLevel = .info,  callback:@escaping (APIResult)->Void){
            let queue = useMainQueue ? DispatchQueue.main : DispatchQueue.global()
            //登录API的出错日志比较特殊
            let urlString = host+url.rawValue
            func logErrorAndCallback(response:NetworkingResult<String>,errNo:Int?=nil, info:String? = nil) {
                logError("url",urlString)
                logError("params",params?.jsonString)
                if response.error != nil {
                    logError("error",response.error!.localizedDescription)
                }
                logError("data",response.data)
                callback(APIResult(success: false,
                                   error: response.error,
                                   errNo: errNo,
                                   errMsg: info ?? "数据解析失败，请稍候再试",
                                   data: errNo != nil ? nil : ["data":response.data]))
                
            }

            print("URL:\(String(describing: urlString)) \n ")
            print("PostData:\n" + (anyToString(params?.jsonString) ?? ""))
            Networking.formString(urlStr: urlString, params: params ,queue:queue) { (response) in
                if response.success && response.error == nil {
                    if let result =  response.data?.trim().toJSONDictionary() {
                        print("result:\n \(String(describing: result.jsonString))" )
                        
                        if let errNo = anyToInt(result[CODE] ?? 0), errNo == 1 {
                            callback(APIResult(success: true,
                                               error: response.error,
                                               errNo: errNo,
                                               errMsg: result.getString(MSG) ?? result.getString(MESSAGE),
                                               data: result))

                        }else{
                            //获取errNo失败
    //                        logErrorAndCallback(response: response, errNo: nil, info: "获取失败，请稍候再试")
                            let errNo = anyToInt(result[CODE] ?? 0)
                            callback(APIResult(success: false,
                                               error: response.error,
                                               errNo: errNo,
                                               errMsg: result.getString(MSG) ?? result.getString(MESSAGE),
                                               data: result))
                            return
                        }
                    }else{
                        //解析Json失败
                        print("result:\n \(String(describing: response.data?.trim()))" )
                        logErrorAndCallback(response: response, errNo: nil, info: "Json失败，请稍候再试")
                        return
                    }
                }else{
//                    let popup = PopupBox(infoText: "网络不可用，请检查网络")
//                    popup.show(vc: UIViewController.topMostController() ?? UIViewController())
                    //网络请求失败
                    print("result:\n \(String(describing: response.data?.trim()))" )
                    logErrorAndCallback(response: response, errNo: nil, info: "网络访问无法完成，请稍候再试")
                    return
                }
            }
        }
    
    
    static func showDefultVC() {
        let vc = DefultVC()
        UIViewController.topMostController()?.pushViewController(vc)
    }
    
    static func sendTokenTomeout() {
        let noT = NSNotification.Name(rawValue: USER_TOKENTIMEOUT)
        let dic = ["key":"value"]
        NotificationCenter.default.post(name: noT, object: nil, userInfo:dic)
    }
    
    ///全局变量，进行checkStep的回调
    ///第一个参数是提示信息
    ///第二个参数，则为用户确认时，重新执行API调用的闭包
    ///第三个参数，为用户放弃时，放弃操作的闭包
    static var CHECK_STEP_FOR_CALL_API : ( (String, @escaping()->(),@escaping()->() )->() )? = nil

//    100  订单类型
//    101  第三方订单
//    103  配送方式
//    104  订单状态
//    105  专区标识
//    106  分页排序方向
//    107  分页排序方式标识
//    108  积分流水历史记录流水类型
//    109  商品库存状态
//    110  短信用途
//    111  检查短信验证码及验证凭证时自身用途
//    116  用户信息性别
    static func requestCode(pCode: String,callback:@escaping ([String:Any?]?)->Void) {
        let identityToken = LocalStorage.getString(forKey: USER_IDENTITYTOKEN)
        
        let params :[String:Any] = ["identityToken":identityToken ?? "",
                                    "pCode":pCode,
                                    "pageIndex":1,
                                    "pageSize":200]
        
        API.request(url: .DicCode, params: params) { (result) in
            
            if result.success {
               if let dl = result.data?.getDictionary("data") {
                   callback(dl)
               }
            }else{
                callback(nil)
            }
        }
    }
    
    
    static func sendVerifyCode(pCode: String,callback:@escaping ([String:Any?]?)->Void) {
        let identityToken = LocalStorage.getString(forKey: USER_IDENTITYTOKEN)
        
        let params :[String:Any] = ["identityToken":identityToken ?? "",
                                    "smsUsesCode":pCode]
        
        API.request(url: .SendVerifyCode, params: params) { (result) in
            
            if result.success {
               if let dl = result.data?.getDictionary("data") {
                   callback(dl)
               }
               else {
                   if let vc = UIViewController.topMostController() {
                       let popup = PopupSureBox(title: result.errMsg ?? "获取验证码失败", sureText: "确定")
                       popup.show(vc: vc)
                       popup.onSureButtonClick = {
                       }
                       callback(nil)
                   }
                }
            }else{
                if let vc = UIViewController.topMostController() {
                    let popup = PopupSureBox(title: result.errMsg ?? "获取验证码失败", sureText: "确定")
                    popup.show(vc: vc)
                    popup.onSureButtonClick = {
                    }
                    callback(nil)
                }
            }
        }
    }
}

/**
 使用字符串url地址调用网络请求,这个方法用于接口自动解析生成的调用方法
 */
func callAPI(url:String,params:[String:Any],useMainQueue:Bool = true,loggingLevel:DDLogLevel = .info,callback:@escaping (APIResult)->Void){
//    let urlString = API.APIPrefix+url
    let urlString = url
    Networking.queryJson(urlStr: urlString, params: params,queue: useMainQueue ? DispatchQueue.main : DispatchQueue.global() ) {
        (response:NetworkingResult<[String:Any?]>) in
        ///发成错误时的日志和回调处理
        ///info: 只在网络访问失败，或者data无法解析的时候提供，其他情况会自动获取errMsg
        func logErrorAndCallback(errNo:Int?,info:String?=nil,data:[String:Any?]?=nil){
            logError("API.request failure")
            logError("url",urlString)
            logError("params",params.jsonString)
            if response.error != nil {
                logError("error",response.error?.localizedDescription)
            }else  if info != nil {
                logError(info)
            }
            if (errNo == nil) && (response.data?.count ?? 0 > 0) {
                if (response.data!.keys).contains("_content") {
                    let result = response.data?["_content"]
                    if let r0 = result,let r1 = r0 {
                        logError("content:","\(r1)(\(type(of: r1)))")
                    }else{
                       logError("(_content is nil)")
                    }
                }else{
                    logError(response.data?.jsonString)
                }
            }

            if errNo != nil {
                logError(response.data?.jsonString)
            }

            let errMsg : String
            if info != nil {
                errMsg = info!
            }else {
                let dataMsg = data?.getString(API.MSG)
                if dataMsg?.count ?? 0 > 0 {
                    errMsg = dataMsg!
                }else{
                    errMsg = "错误发生，请稍候再试"
                }
            }

            callback(APIResult(success: false,
                               error: response.error,
                               errNo: errNo,
                               errMsg: errMsg,
                               data: response.data))
        }

        if !response.success || response.error != nil {
            logErrorAndCallback(errNo: nil,info: "网络访问无法完成，请稍候再试")
            return
        }
        if let data = response.data,data.getString(API.RESULT) == "success" {
            let errNo = data.getInt(API.CODE)
            if errNo != 0 {
                //一个特殊处理，如果 errNo > 500，让客户确认，如果客户认可，则把errNo+1当做checkStep传入，重新提交
//                if (API.CHECK_STEP_FOR_CALL_API != nil) && (errNo ?? 0 >= 500) {
//                    let errMsg = data.getString(API.MSG) ?? "(提示信息无法获取)"
//                    let onSure = {
//                        var nextP = params
//                        nextP["checkStep"] = errNo+1
//                        //再次调用
//                        callAPI(url:url,params:nextP,useMainQueue:useMainQueue,loggingLevel: loggingLevel, callback:callback)
//                    }
//                    let onCancel = {
//                        logErrorAndCallback(errNo: errNo, data: data)
//                    }
//                    API.CHECK_STEP_FOR_CALL_API!(errMsg,onSure,onCancel)
//                    return
//                }
                logErrorAndCallback(errNo: errNo, data: data)
                return
            }

            _log2(level: loggingLevel, "url",urlString)
            _log2(level: loggingLevel, "params",params.jsonString)
            _log2(level: loggingLevel, "response",data.jsonString)
            callback(APIResult(success: true,
                               error: response.error,
                               errNo: errNo,
                               errMsg: data.getString(API.MSG),
                               data: data))
        }else{
            //获取权限，作为特例，可以允许errNo=null
            if let data = response.data,urlString.contains("hasprivileges.action"),data.getInt(API.CODE) == nil {
                _log2(level: loggingLevel, "url",urlString)
                _log2(level: loggingLevel, "params",params.jsonString)
                _log2(level: loggingLevel, "response",data.jsonString)
                callback(APIResult(success: true,
                                   error: response.error,
                                   errNo: nil,
                                   errMsg: data.getString(API.MSG),
                                   data: data))
                return
            }
            logErrorAndCallback(errNo: nil,info: "数据解析失败，请稍候再试",data:response.data)
            return
        }
    }
}


///抽象的分页逻辑
class Pageable {
    
    var start : Int = 0
    let pageSize : Int
    
    ///当前页数（从0开始)
    var currentPage : Int = -1
    
    ///当前页是否是最后一页（最后一次获取的记录数是否小于pageSize）
    var isLastPage : Bool = false
    
    init(pageSize:Int = 20){
        assert( pageSize > 0)
        self.pageSize = pageSize
    }
    
    ///重新定位至第一页
    func resetPage(){
        start = 0
        currentPage = 0
        isLastPage = false
    }
    
    ///记录当前页数据，判断是否到了最后一页
    ///自动翻页至下一页
    func recordAndNext(size:Int){
        currentPage += 1
        start += pageSize
        if size < pageSize {
            isLastPage = true
        }
    }
    
}

///查询结果为分页记录的API
///用法：自己实现url属性，params属性，实现convert进行对象转换，或者实现convertList直接转换整个列表
///定制getDictList获取列表，也可以直接定制整个query
class PageableAPI<T> : Pageable {
    var url : String { get { fatalError("wait implement") }  }
    var params : [String:Any] { get { fatalError("wait implement") }  }
    //当前查询结果
    var list : [T] = []
    var startField : String { return "start"}
    var pageSizeField : String { return "pageSize"}
    func query(reset:Bool = false,callback:@escaping (_ result:APIResult)->Void){
        if reset {
            resetPage()
        }
        var params = self.params
        params[startField] = start
        params[pageSizeField] = pageSize
        callAPI(url: self.url,  params: params, loggingLevel: .debug) { result in
            if result.success{
                if reset {
                    self.list = []
                }
                if let listData = self.getDictList(result.data) {
                    self.list = self.list + self.convertList(jsonList: listData)
                    self.recordAndNext(size: listData.count)
                }else{
                    let newResult = APIResult.init(success: false, error: result.error, errNo: result.errNo,
                                                   errMsg: "无法解析接口返回信息，请稍后再试",
                                                   data: result.data)
                    callback(newResult)
                    return
                }
            }
            callback(result)
        }
    }
    
    func getDictList(_ data:[String:Any?]?)->[[String:Any?]]?{
        return data?.getDictList("listData")
    }
    
    ///将整个json数组转成目标数组
    func convertList(jsonList:[[String:Any?]])->[T]{
         return jsonList.map { self.convert(json: $0) }
    }
    
    ///将json转换成目标数据结构
    func convert(json:[String:Any?])->T{
        fatalError("should implement")
    }
}

class PageableJsonAPI : PageableAPI<[String:Any?]>{
    ///将整个json数组转成目标数组
    override func convertList(jsonList:[[String:Any?]])->[[String:Any?]]{
        return jsonList
    }
}
